﻿using General.Core.Data;
using System;
using System.Collections.Generic;
using System.Text;
using General.Entities;
using System.Linq;
using General.Core.Librs;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.EntityFrameworkCore;
using General.Core;
using General.Core.Infrastructure;

namespace General.Services.SysUser
{
    public class SysUserService : ISysUserService
    {
        private IMemoryCache _memoryCache;
        private readonly static string MODEL_KEY = "General.services.user_{0}";
        private readonly static int DAYS = 15;

        private IWebHelper _webHelper;
        private GeneralDbContext _generalDbContext;

        public SysUserService(GeneralDbContext generalDbContext,
            IWebHelper webHelper,
            IMemoryCache memoryCache)
        {
            this._webHelper = webHelper;
            this._generalDbContext = generalDbContext;
            this._memoryCache = memoryCache;
        }

        /// <summary>
        /// 验证登录状态
        /// </summary>
        /// <param name="account">登录账号</param>
        /// <param name="password">登录密码</param>
        /// <param name="r">登录随机数</param>
        /// <returns></returns>
        public (bool Status, string Message, string Token, Entities.SysUser User) ValidateUser(string account, string password)
        {
            var user = GetByAccount(account);
            if (user == null)
                return (false, "用户名或密码错误", null, null);
            if (!user.Enabled)
                return (false, "你的账号已被冻结", null, null);
            if (user.LoginLock)
            {
                if (user.AllowLoginTime > DateTime.Now)
                {
                    return (false, "账号已被锁定" + ((int)(user.AllowLoginTime - DateTime.Now).Value.TotalMinutes + 1) + "分钟。", null, null);
                }
            }
            //匹配密码
            if (password.Equals(user.Password, StringComparison.InvariantCultureIgnoreCase))
            {
                user.LoginLock = false;
                user.LoginFailedNum = 0;
                user.AllowLoginTime = null;
                user.LastLoginTime = DateTime.Now;
                user.LastIpAddress = _webHelper.GetIPAddress();

                //登录日志
                user.SysUserLoginLogs.Add(new SysUserLoginLog()
                {
                    Id = Guid.NewGuid(),
                    IpAddress = user.LastIpAddress,
                    LoginTime = DateTime.Now,
                    Message = "登录：成功"
                });
                //单点登录,移除旧的登录token
                var userToken = new SysUserToken()
                {
                    Id = Guid.NewGuid(),
                    ExpireTime = DateTime.Now.AddDays(15)
                };
                user.SysUserTokens.Add(userToken);
                _generalDbContext.SaveChanges();
                return (true, "登录成功", userToken.Id.ToString(), user);
            }
            else
            {
                //登录日志
                user.SysUserLoginLogs.Add(new SysUserLoginLog()
                {
                    Id = Guid.NewGuid(),
                    IpAddress = user.LastIpAddress,
                    LoginTime = DateTime.Now,
                    Message = "登录：密码错误"
                });
                user.LoginFailedNum++;
                if (user.LoginFailedNum > 5)
                {
                    user.LoginLock = true;
                    user.AllowLoginTime = DateTime.Now.AddHours(2);
                }
                _generalDbContext.SaveChanges();
            }
            return (false, "用户名或密码错误", null, null);
        }

        /// <summary>
        /// 通过账号获取用户
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public Entities.SysUser GetByAccount(string account)
        {
            return _generalDbContext.SysUsers.FirstOrDefault(o => o.Account == account && !o.IsDeleted);
        }

        /// <summary>
        /// 通过当前登录用户的token 获取用户信息，并缓存
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public Entities.SysUser GetLogged(string token)
        {
            Entities.SysUserToken userToken = null;
            Entities.SysUser sysUser = null;
            if (!_memoryCache.TryGetValue<Entities.SysUserToken>(token, out userToken))
            {
                Guid tokenId = Guid.Empty;
                if (Guid.TryParse(token, out tokenId))
                {
                    userToken = _generalDbContext.SysUserTokenes.FirstOrDefault(o => o.Id == tokenId);
                    if (userToken != null)
                        _memoryCache.Set(token, userToken, DateTimeOffset.Now.AddDays(DAYS));
                }
            }
            if (userToken != null)
            {
                if (!_memoryCache.TryGetValue(String.Format(MODEL_KEY, userToken.SysUserId), out sysUser))
                {
                    sysUser = _generalDbContext.SysUsers.FirstOrDefault(o => o.Id == userToken.SysUserId);
                    _memoryCache.Set(String.Format(MODEL_KEY, userToken.SysUserId), sysUser, DateTimeOffset.Now.AddDays(DAYS));
                }
            }
            return sysUser;
        }

        /// <summary>
        /// 搜索数据
        /// </summary>
        /// <param name="arg"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public IPagedList<Entities.SysUser> SearchUser(SysUserSearchArg arg, int page, int size)
        {
            var query = _generalDbContext.SysUsers.Where(o => !o.IsDeleted);
            if (arg != null)
            {
                if (!String.IsNullOrEmpty(arg.q))
                    query = query.Where(o => o.Account.Contains(arg.q) || o.MobilePhone.Contains(arg.q) || o.Email.Contains(arg.q) || o.Name.Contains(arg.q));
                if (arg.enabled.HasValue)
                    query = query.Where(o => o.Enabled == arg.enabled);
                if (arg.unlock.HasValue)
                    query = query.Where(o => o.LoginLock == arg.unlock);
                if (arg.roleId.HasValue)
                    query = query.Where(o => o.SysUserRoles.Any(r => r.RoleId == arg.roleId));
            }
            query = query.OrderBy(o => o.Account).ThenBy(o => o.Name).ThenByDescending(o => o.CreationTime);
            query = query.Select(item => new Entities.SysUser()
            {
                Id = item.Id,
                Name = item.Name,
                MobilePhone = item.MobilePhone,
                Sex = item.Sex,
                LastActivityTime = item.LastActivityTime,
                Account = item.Account,
                Enabled = item.Enabled,
                IsAdmin = item.IsAdmin,
                LoginLock = item.LoginLock,
                SysRoles = item.SysUserRoles.Select(x => x.SysRole).ToList()
            });
            return new PagedList<Entities.SysUser>(query, page, size);
        }

        /// <summary>
        /// 获取用户详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Entities.SysUser GetById(Guid id)
        {
            return _generalDbContext.SysUsers.Find(id);
        }

        /// <summary>
        /// 新增，插入
        /// </summary>
        /// <param name="model"></param>
        public (bool Status, string Message) InsertSysUser(Entities.SysUser model)
        {
            if (ExistAccount(model.Account))
                return (false, "账号已存在");
            model.SysUserNotes.Add(new SysUserNote()
            {
                Id = Guid.NewGuid(),
                MsgContent = "创建用户。账号：" + model.Account,
                CreationTime = DateTime.Now,
                Creator = model.Creator.Value
            });
            _generalDbContext.SysUsers.Add(model);
            _generalDbContext.SaveChanges();
            return (true, "添加成功");
        }

        /// <summary>
        /// 更新修改
        /// </summary>
        /// <param name="model"></param>
        public (bool Status, string Message) UpdateSysUser(Entities.SysUser model)
        {
            var user = GetById(model.Id);
            user.Name = model.Name;
            user.Email = model.Email;
            user.MobilePhone = model.MobilePhone;
            user.Sex = model.Sex;
            user.SysUserNotes.Add(new SysUserNote()
            {
                Id = Guid.NewGuid(),
                CreationTime = DateTime.Now,
                Creator = model.Modifier.Value,
                MsgContent = "更改用户信息。姓名：" + model.Name + "，性别：" + model.Sex + "，手机号：" + model.MobilePhone + "，邮箱：" + model.Email
            });
            _generalDbContext.SaveChanges();
            RemoveCacheUser(model.Id);
            return (true, "修改成功");
        }

        /// <summary>
        /// 重置密码。默认重置成账号一样
        /// </summary>
        /// <param name="id"></param>
        /// <param name="modifer"></param>
        public void ResetPassword(Guid id, Guid modifer)
        {
            var user = GetById(id);
            user.Password = EncryptorHelper.GetMD5(user.Account + user.Salt);
            user.ModifiedTime = DateTime.Now;
            user.Modifier = modifer;
            user.SysUserNotes.Add(new SysUserNote()
            {
                Id = Guid.NewGuid(),
                CreationTime = DateTime.Now,
                Creator = modifer,
                MsgContent = "重置用户密码。"
            });
            _generalDbContext.SaveChanges();
        }

        /// <summary>
        /// 验证账号是否已经存在
        /// </summary>
        /// <param name="id"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public bool ExistAccount(string account)
        {
            return _generalDbContext.SysUsers.Any(o => o.Account == account && !o.IsDeleted);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="ulock"></param>
        /// <param name="modifer"></param>
        public void LoginLock(Guid id, bool ulock, Guid modifer)
        {
            var user = _generalDbContext.SysUsers.Local.FirstOrDefault(o => o.Id == id);
            if (user != null)
            {
                user.LoginLock = ulock;
                user.ModifiedTime = DateTime.Now;
                user.Modifier = modifer;
            }
            else
            {
                var entry = _generalDbContext.Entry(new Entities.SysUser() { Id = id, LoginLock = ulock, Modifier = modifer, ModifiedTime = DateTime.Now });
                entry.State = EntityState.Unchanged;
                entry.Property("LoginLock").IsModified = true;
                entry.Property("ModifiedTime").IsModified = true;
                entry.Property("Modifier").IsModified = true;
            }
            _generalDbContext.SaveChanges();
            RemoveCacheUser(id);
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="id"></param>
        /// <param name="modifer"></param>
        public void DeleteUser(Guid id, Guid modifer)
        {
            var user = new Entities.SysUser() { Id = id, IsDeleted = true, DeletedTime = DateTime.Now, Modifier = modifer, ModifiedTime = DateTime.Now };
            var entry = _generalDbContext.Entry(user);
            entry.State = EntityState.Unchanged;
            entry.Property("ModifiedTime").IsModified = true;
            entry.Property("Modifier").IsModified = true;
            entry.Property("IsDeleted").IsModified = true;
            entry.Property("DeletedTime").IsModified = true;
            user.SysUserNotes.Add(new SysUserNote()
            {
                Id = Guid.NewGuid(),
                CreationTime = DateTime.Now,
                Creator = modifer,
                MsgContent = "删除用户。"
            });
            _generalDbContext.SaveChanges();
            RemoveCacheUser(id);
        }

        /// <summary>
        /// 保存头像信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="avatar"></param>
        public void AddAvatar(Guid id, byte[] avatar)
        {
            var user = _generalDbContext.SysUsers.Local.FirstOrDefault(o => o.Id == id);
            if (user != null)
            {
                user.Avatar = avatar;
                user.ModifiedTime = DateTime.Now;
            }
            else
            {
                var entry = _generalDbContext.Entry(new Entities.SysUser() { Id = id, ModifiedTime = DateTime.Now, Avatar = avatar });
                entry.State = EntityState.Unchanged;
                entry.Property("Avatar").IsModified = true;
                entry.Property("ModifiedTime").IsModified = true;
                _generalDbContext.SaveChanges();
            }
            RemoveCacheUser(id);
        }

        /// <summary>
        /// 用户自己修改用户密码
        /// </summary>
        /// <param name="id"></param>
        /// <param name="password"></param>
        public void ChangePassword(Guid id, string password)
        {
            var user = _generalDbContext.SysUsers.Local.FirstOrDefault(o => o.Id == id);
            if (user != null)
            {
                user.Password = password;
            }
            else
            {
                var entry = _generalDbContext.Entry(new Entities.SysUser() { Id = id, ModifiedTime = DateTime.Now, Password = password });
                entry.State = EntityState.Unchanged;
                entry.Property("Password").IsModified = true;
                entry.Property("ModifiedTime").IsModified = true;
            }
            _generalDbContext.SaveChanges();
        }

        /// <summary>
        /// 更新活动时间
        /// </summary>
        /// <param name="id"></param>
        public void LastActivityTime(Guid id)
        { var user = _generalDbContext.SysUsers.Local.FirstOrDefault(o => o.Id == id);
            if (user != null)
            {
                user.LastActivityTime = DateTime.Now;
            }
            else
            {
                var entry = _generalDbContext.Entry(new Entities.SysUser() { Id = id, ModifiedTime = DateTime.Now, LastActivityTime = DateTime.Now });
                entry.State = EntityState.Unchanged;
                entry.Property("LastActivityTime").IsModified = true;
            }
            _generalDbContext.SaveChanges();
        }

        /// <summary>
        /// 移除缓存用户
        /// </summary>
        /// <param name="userId"></param>
        private void RemoveCacheUser(Guid userId)
        {
            string key = String.Format(MODEL_KEY, userId);
            _memoryCache.Remove(key);
        }
    }
}
